use std::path::{Path, PathBuf};

use dotenv::dotenv;
use entity::sea_orm::{ConnectionTrait, Statement};
use sea_orm_migration::prelude::*;

pub struct Migration;

impl MigrationName for Migration {
    fn name(&self) -> &str {
        "m20220521_223848_view_book_pub_status"
    }
}

#[async_trait::async_trait]
impl MigrationTrait for Migration {
    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
        apply_sql_migration("view_book_pub_status", manager).await
    }

    async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
        undo_sql_migration("view_book_pub_status", manager).await
    }
}

fn load_sql_migration() -> String {
    dotenv().ok();
    dotenv::var("SQL_MIGRATION").unwrap_or("./migration_sql".into())
}

pub async fn apply_sql_migration(name: &str, manager: &SchemaManager<'_>) -> Result<(), DbErr> {
    let path = Path::new(&load_sql_migration()).join(name).join("up.sql");
    apply_sql(&path, manager).await
}
pub async fn undo_sql_migration(name: &str, manager: &SchemaManager<'_>) -> Result<(), DbErr> {
    let path = Path::new(&load_sql_migration()).join(name).join("down.sql");
    apply_sql(&path, manager).await
}

async fn apply_sql(path: &PathBuf, manager: &SchemaManager<'_>) -> Result<(), DbErr> {
    let sql = async_std::fs::read_to_string(path)
        .await
        .expect("文件不存在");

    manager
        .get_connection()
        .execute(Statement::from_string(manager.get_database_backend(), sql))
        .await?;
    Ok(())
}
